import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class ApplicationPanel extends JPanel {

	private ImagePanel imagePanel;
	private static final long serialVersionUID = 1L;

	/**
	 * Constructor for Application Panel
	 */
	public ApplicationPanel() {
		setLayout(new BorderLayout());
		add(createMenu(), BorderLayout.NORTH);
		imagePanel = new ImagePanel(new Image());
		add(imagePanel, BorderLayout.CENTER);
		setPreferredSize(new Dimension(300, 300));
	}

	/**
	 * Creates the menu on top by uses of String arrays
	 * 
	 * @return JMenuBar with all options for program
	 */
	private JMenuBar createMenu() {
		JMenuBar topMenu = new JMenuBar();
		String[] labelsForFile = { "File", "Save", "Open", "Close" };
		topMenu.add(addMenu(labelsForFile));
		String[] labelsForFunctions = { "Functions", "New Image Size",
				"Rotate", "Clear Image" };
		topMenu.add(addMenu(labelsForFunctions));
		String[] labelsForColors = { "Change Color", "Red", "White", "Blue",
				"Green", "Black", "Yellow", "Cyan" };
		topMenu.add(addMenu(labelsForColors));
		String[] labelsForBackground = { "Background", "Red", "White", "Blue",
				"Green", "Black", "Yellow", "Cyan" };
		topMenu.add(addMenu(labelsForBackground));
		String[] labelsForBrush = { "Brush Size", "Small", "Medium", "Large" };
		topMenu.add(addMenu(labelsForBrush));
		return topMenu;
	}

	/**
	 * This function takes labels and creates functional menus for a menu bar.
	 * Also, it adds actionListeners to the menus so they work.
	 * 
	 * @param labels
	 *            An array of Strings with the menu name first and menu items
	 *            after
	 * @return A menu to be added to a menu bar
	 */
	private JMenu addMenu(String[] labels) {
		JMenu file = new JMenu(labels[0]);
		for (int i = 1; i < labels.length; i++) {
			JMenuItem jmi = new JMenuItem(labels[i]);
			if (labels[0].equals("Background")
					|| labels[0].equals("Brush Size")) {
				jmi.addActionListener(new MenuListenerAdvanced());
			} else {
				jmi.addActionListener(new MenuListener());
			}
			file.add(jmi);
		}
		return file;
	}

	/**
	 * Opens a saved file as an Image
	 * 
	 * @param fname
	 *            File to be opened
	 */
	public void open(String fname) {
		try {
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
					fname));
			Image img = (Image) ois.readObject();
			imagePanel.setImage(img);
			imagePanel.setPaintSize(1);
			repaint();
			paintChildren(this.getGraphics());
			imagePanel.setPaintSize(2);
			ois.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	/**
	 * Saves a files as an Image
	 * 
	 * @param fname
	 *            File for saving
	 */
	public void save(String fname) {
		try {
			ObjectOutputStream ois = new ObjectOutputStream(
					new FileOutputStream(fname));
			ois.writeObject(imagePanel.getImage());
			ois.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	/**
	 * This method checks to see if an action event's action command is
	 * translatable to change brush size
	 * 
	 * @param e
	 *            Action event
	 * @return The size of the brush needed
	 */
	private int checkSize(ActionEvent e) {
		if (e.getActionCommand().equals("Small")) {
			return 1;
		}
		if (e.getActionCommand().equals("Medium")) {
			return 2;
		}
		if (e.getActionCommand().equals("Large")) {
			return 3;
		}
		return -1;
	}

	/**
	 * Checks to see if an Action Event's action command is translatable to a
	 * change of color
	 * 
	 * @param e
	 *            Action Event
	 * @return The color index of the color
	 */
	private int checkColors(ActionEvent e) {
		if (e.getActionCommand().equals("Red")) {
			return 1;
		}
		if (e.getActionCommand().equals("White")) {
			return 0;
		}
		if (e.getActionCommand().equals("Green")) {
			return 2;
		}
		if (e.getActionCommand().equals("Blue")) {
			return 3;
		}
		if (e.getActionCommand().equals("Black")) {
			return 4;
		}
		if (e.getActionCommand().equals("Yellow")) {
			return 5;
		}
		if (e.getActionCommand().equals("Cyan")) {
			return 6;
		} else {
			return -1;
		}
	}
	/**
	 * Does the correct closing operation
	 * @param choose File Chooser
	 */
	public void close(JFileChooser choose) {
		int confirm = JOptionPane.showConfirmDialog(null,
				"Close without saving?");
		if (confirm == JOptionPane.NO_OPTION) {
			int input = choose.showSaveDialog(null);
			if (input == JFileChooser.APPROVE_OPTION) {
				save(choose.getSelectedFile().getAbsolutePath());
			}
			System.exit(0);
		} else if (confirm == JOptionPane.OK_OPTION) {
			System.exit(0);
		}
	}

	/**
	 * Action Listener used on the required options (save, close, open, rotate,
	 * etc.)
	 * 
	 * @author Andrew Oberlin
	 * 
	 */
	private class MenuListener implements ActionListener {
		/**
		 * Determines what action is to be performed
		 */
		public void actionPerformed(ActionEvent e) {
			JFileChooser choose = new JFileChooser(".");
			if (e.getActionCommand() == "Save") {
				int input = choose.showSaveDialog(null);
				if (input == JFileChooser.APPROVE_OPTION) {
					save(choose.getSelectedFile().getAbsolutePath());
				}
			} else if (e.getActionCommand() == "Open") {
				int input = choose.showOpenDialog(null);
				if (input == JFileChooser.APPROVE_OPTION) {
					open(choose.getSelectedFile().getAbsolutePath());
				}
			} else {
				if (e.getActionCommand() == "Close") {
					close(choose);
				}
				if (e.getActionCommand() == "New Image Size") {
					int i = Integer.parseInt(JOptionPane
							.showInputDialog("Enter x Size"));
					int j = Integer.parseInt(JOptionPane
							.showInputDialog("Enter y Size"));
					imagePanel.changeSize(i,j);
				}
				if (e.getActionCommand() == "Rotate") {
					imagePanel.rotateImage();
				}
				if (e.getActionCommand() == "Clear Image") {
					imagePanel.clearImage();
				}
				int colorToChange = checkColors(e);
				if (colorToChange >= 0) {
					imagePanel.setCurrColor(colorToChange);
				}
			}
		}
	}

	/**
	 * An Action Listener that is used to control the extra options (background
	 * color and brush size)
	 * 
	 * @author Andrew Oberlin
	 * 
	 */
	private class MenuListenerAdvanced implements ActionListener {

		/**
		 * Determines what action is to be performed
		 */
		public void actionPerformed(ActionEvent e) {
			int colorToChange = checkColors(e);
			if (colorToChange >= 0) {
				imagePanel.setBackgroundColor(colorToChange);
			}
			int brushSize = checkSize(e);
			if (brushSize >= 0) {
				imagePanel.setPaintSize(brushSize);
			}
		}
	}
}